#include <QMap>
#include "sensordataprocess.h"
#include "macro.h"
#include "DBO/db.h"
#include "QSqlQuery"
#include "QSqlError"

SensorDataProcess::SensorDataProcess(QObject *parent) :
    QObject(parent)
{
    mapIDInNodeSensorMap_Event=new QMap<qint32,QByteArray>;
    dbo=new DatabaseOperation(this);

    if(!dbo->createConnection(DB_NAME,DB_HOST,DB_USERNAME,DB_PWD,DB_CON_NAME_ADAPTER_SERIALPORT))
    {
        emit  sigError("SensorDataProcess中连接数据库失败: connection "DB_CON_NAME_ADAPTER_SERIALPORT" failed:"
                              +dbo->query->lastError().text());
       exit(10);
    }

    //初始化虚拟传感器信息
    mapRefSensorIDVirtualSensorName=new QMap<qint16,QByteArray>;
    mapRefSensorIDVirtualSensorName->insert(43,"RFIDHolderName"); //RFID对应的是RFID的编号



    QTimer::singleShot(500,this,SLOT(beginOfProgram()));
}

void SensorDataProcess::slotProcessSensorData(QByteArray packet,QHostAddress srcAddress,quint16 srcPort)
{
    bool ok;
    quint64 pktType=packet.mid(PktType_Pos,PktType_Size).toHex().toULongLong(&ok,16);
    statistic(packet.toHex(),srcAddress,srcPort,pktType==PktEventSensorType);
}

void SensorDataProcess::beginOfProgram() //程序开始后的操作
{
    /*下面的语句新建一个数据表,以当前时间命名表的名称
    然后将对应时间存入sensordataindex表。每天建立一张新表。
       将两句话作为一个事务来处理.
       遵循原则:每天有且只有一张数据表（当天有数据的情况下）。
*/
    QSqlQuery tempQuery(QSqlDatabase::database(dbo->dbConnectionName));
    QSqlQuery tempQuery2(QSqlDatabase::database(dbo->dbConnectionName));

    dateTime=QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
    if(tempQuery.exec("select datetimestart,tablename from sensordataindex where datetimestart="
                        "(select max(datetimestart) from sensordataindex)"))
    {        
            if(!tempQuery.next()||tempQuery.value(0).toDateTime().date()!=QDateTime::currentDateTime().date())
            {
                if( !tempQuery2.exec("CREATE TABLE r"+
                      dateTime+
                    " (datetime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,"
                     "seq smallint NOT NULL,"
                     "NodeMacAddress bigint NOT NULL,"
                     "SensorID smallint NOT NULL, "
                      "SensorData varchar(31),"
                        /******因为一些地方不支持外键，所以暂时不用这两句
                       " CONSTRAINT `FK_r"+dateTime+"_SensorID` FOREIGN KEY (`SensorID`) REFERENCES `typemap` (`SensorID`) ON DELETE CASCADE ON UPDATE CASCADE,"
                        " CONSTRAINT `FK_r"+dateTime+"_NodeMac` FOREIGN KEY (`NodeMacAddress`) REFERENCES `nodeaddressmap` (`NodeMacAddress`) ON DELETE CASCADE ON UPDATE CASCADE,"
                           **********/
                     "ID INT  PRIMARY KEY NOT NULL AUTO_INCREMENT,key indTime (datetime),key indMac (NodeMacAddress),key indSensorID (SensorID)"

                      " );"

                      ) )
                {

                    emit sigError("Database Error"+tempQuery2.lastError().text());
                }

                else if(!tempQuery2.exec("INSERT INTO sensordataindex(DateTimeStart, TableName) "
                               " values(" +dateTime+
                                          ", 'r"+
                                          dateTime+"'"+")"
                    )  )
                    //执行回滚
                {
                    emit sigError("Database Error"+tempQuery2.lastError().text());
                    tempQuery2.exec("drop table r"+dateTime+" ;") ;
                }
                else
                {
                   emit sigError("new table created successfully, name is r"+dateTime);
               }

                if(!tempQuery2.exec("alter view rToday as select * from r"+dateTime))
                {
                    emit sigError("Database Error in alter view."+tempQuery2.lastError().text());
                }

            } //if(lastTime!=dateTimeStart.date())结束
            else if(tempQuery.size()>0)//如果当天的表已经建立,获取表的建立时间
            {
               dateTime=tempQuery.value(1).toString().remove(0,1);
               emit sigError("Table created previously, name is r"+dateTime);

            }
    }
    else //如果"select max(DateTimeStart) from sensordataindex"出错
    {
         emit sigError("Database Error"+tempQuery.lastError().text());
    }
}

void SensorDataProcess::insertIntoRData(const QString &Seq, const QString &NodeMacAddress, const QString &SensorID, const QString &SensorData, const QString &DataTime)
{
    QSqlQuery tempQuery(QSqlDatabase::database(dbo->dbConnectionName));

       if(QDateTime::fromString(dateTime,"yyyyMMddhhmmss").date()!=QDateTime::currentDateTime().date())
        beginOfProgram();  //如果跨越了0点，则新建一张表

          if( !tempQuery.exec("insert into r"+
               dateTime+"(Seq,NodeMacAddress,SensorID,SensorData,DateTime)"
               "  values("+Seq+","+NodeMacAddress+","+SensorID+","+SensorData+","+DataTime+")"
             ))
          {
              emit sigError("DataBase ERROR: "+tempQuery.lastError().text());

          }
          else
          {
              tempQuery.exec("update sensordataindex set DateTimeEnd="+
                         DataTime.toLocal8Bit()+
                         "  where DateTimeStart="+
                         dateTime);
         }
}

void SensorDataProcess::statistic(QByteArray packet,QHostAddress srcAddress,quint16 srcPort, bool isEvent)
{
    quint8  SN,SensorId,    sensorDataLength(2);
    qint64 Source; //即 nodeMacAddress
    QByteArray dataByteArray;
    QString expre; expre="@data";//计算公式
    QString result; //数据解析结果，最后存入数据库
    qint64 dataInt64; //传感器原始数据。最大只能8字节
    qint32 IDInNodeSensorMap;
    bool ok;

    QSqlQuery tempQuery(QSqlDatabase::database(dbo->dbConnectionName));

    /**********************解析源地址和SN********************/
    for(int n=0;n<Source_Size*2;n++)
        dataByteArray.append(packet.at(n+Source_Pos*2));
    Source=dataByteArray.toLongLong(&ok,16);

    dataByteArray.clear();

    for(int n=0;n<SN_Size*2;n++)
        dataByteArray.append(packet.at(n+SN_Pos*2));
    SN=dataByteArray.toUShort(&ok,16);
    dataByteArray.clear();

    int p=DataType_Pos*2;
    QByteArray byteSensorID;
    /***********************解析数据负载***************************/
    while(p<packet.length()-2-CRC_Size*2) //解析数据负载
    {
        dataByteArray.append(packet.at(p++));
        dataByteArray.append(packet.at(p++));
        byteSensorID=dataByteArray;
        SensorId=dataByteArray.toUShort(&ok,16);
        dataByteArray.clear();
        if(!( tempQuery.exec("select  DataLength, Expre,ID from nodeSensorMap"
                   " where NodeMacAddress="+QString::number(Source,10)+
                   " and SensorID="+QString::number(SensorId,10)
                   ) ) )
        {
            emit sigError("Database Error"+tempQuery.lastError().text());
            return; //退出
               // sensorDataLength=2; //默认数据长度
                //expre="@data";
         }
        else
        {
            if(tempQuery.next()) //判断是否有符合的结果
            {
                sensorDataLength=tempQuery.value(0).toUInt(&ok); //数据长度，单位为字节
                expre=tempQuery.value(1).toString(); //计算公式
                IDInNodeSensorMap=tempQuery.value(2).toInt(&ok);
                if(expre.isEmpty())
                    expre="@data";

                emit sigInfo("传感器类型编号为："+QByteArray::number(SensorId)+".传感器数据字节数为："
                             +QByteArray::number(sensorDataLength)+".传感器数据计算的表达式为："+expre);
            }
            else
            {
                QByteArray configPacket=packet;
                //从reserved开始替换，形成一个配置信息包,发送给IOTServer，说明有未注册的传感器
                QByteArray configSensorReservedToCRC;
                configSensorReservedToCRC.append("01"); //reserved
                configSensorReservedToCRC.append(mySetNumHex(NodeInfoSensors,2));
                configSensorReservedToCRC.append(byteSensorID);
                configSensorReservedToCRC.append("ffff");

                configPacket.chop(configPacket.size()-DataType_Pos*2+2);
                configPacket.append(configSensorReservedToCRC);
                configPacket.replace(PktType_Pos*2,PktType_Size*2,mySetNumHex(PktNodeInfo,2));

                QByteArray lenByte;
                quint16 len=configPacket.size()/2-4;
                lenByte=mySetNumHex(len,Len_Size*2);
                configPacket.replace(Len_Pos*2,Len_Size*2,lenByte);

                emit sigPacketNodeToServer(QByteArray::fromHex(configPacket),srcAddress,srcPort,false);
                emit sigInfo(QString::number(Source,10)+tr("没有找到合适的解析公式.SensorID is "+QByteArray::number(SensorId))+
                             "\nConfig Packet to IOTServer is "+configPacket);
                return; //结束
            }
        }
        int num;
        for(num=0; num<sensorDataLength*2;num++)
            dataByteArray.append(packet.at(p+num));

        emit sigInfo("传感器的数据内容为:"+dataByteArray);


        dataInt64=dataByteArray.toLongLong(&ok,16);
        if(ok) //转换成功，当databytearray不大于8字节时，一般会成功
        {
            expre.replace("@data",QString::number(dataInt64,10));
            if(!tempQuery.exec("select "+expre))
            {
                emit sigError(tr("Database Error to select expre.")+tempQuery.lastError().text()+
                                     "\nExpre is '"+expre+"'");
                return;
            }
            if(tempQuery.next())
                result=tempQuery.value(0).toString();
            else
                result=dataByteArray;
        }
        else
            result=dataByteArray; //大于8字节的情况。存储16进制内容。

        dataByteArray.clear();
        if(result.isEmpty())
        {
            emit sigInfo("result is empty");
            return;
        }


        QString stringCurrentDateTime=QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
        insertIntoRData(QString::number(SN,10),QString::number(Source,10),
                            QString::number(SensorId,10),result,stringCurrentDateTime);
        /*对事件包进行处理，向IOTServer汇报事件*/
        if(isEvent)
        {
            updateLastEventDataInNodeSensorMap(IDInNodeSensorMap,result.toUtf8());
            if(tempQuery.exec("select SensorName from typemap where SensorID="+QString::number(SensorId,10)))
            {
                if(tempQuery.next())
                {
                    QByteArray dataToBeSent="Event Notify "+QByteArray::number(Source,10)+" SensorData "+
                        tempQuery.value(0).toByteArray()+" "+result.toUtf8();
                    emit sigEventNotify(dataToBeSent,srcAddress.toString(),srcPort);
                    //接下来查看有没有对应的虚拟传感器
                    if(mapRefSensorIDVirtualSensorName->contains(SensorId))
                    {
                        if(SensorId==SENSORID_RFID)
                        {
                            QSqlQuery tempQuery2(QSqlDatabase::database(dbo->dbConnectionName));

                            if(tempQuery2.exec("select UserName from rfidinfo where CardID="+result))
                            {
                                if(tempQuery2.next())
                                {
                                    QByteArray userName=tempQuery2.value(0).toByteArray();
                                    dataToBeSent="Event Notify "+QByteArray::number(Source,10)+" SensorData "+
                                            mapRefSensorIDVirtualSensorName->value(SensorId)+" "+userName;
                                    emit sigEventNotify(dataToBeSent,srcAddress.toString(),srcPort);
                                }
                            }

                        }
                    }
                }
                else
                    emit sigInfo("No sensorname is found for sensorid "+QString::number(SensorId,10));
            }
            else
                emit sigError(tr("Database Error")+tempQuery.lastError().text());
        }
        else
            emit sigInfo("sensor data "+result+" is inserted into database");
        /************事件包处理结束********************/


        p=p+num;
    } //while(p<=dbo->packetLen-1-dbo->pCRCSize/4-3) 结束，即数据负载解析结束
 /*****************数据负载解析结束*********************************************/
}

void SensorDataProcess::updateLastEventDataInNodeSensorMap(qint32 ID,QByteArray data)
{
    QSqlQuery tempQuery(QSqlDatabase::database(dbo->dbConnectionName));
    //如果数据发生了变化，则更新表格NodeSensormap
    if(!mapIDInNodeSensorMap_Event->contains(ID)||mapIDInNodeSensorMap_Event->value(ID)!=data)
    {
        mapIDInNodeSensorMap_Event->insert(ID,data);

        if(!tempQuery.exec("update NodeSensorMap set LastEventData='"+data+
                            "' where ID="+QString::number(ID,10)))
            emit sigError(tr("ERROR：更新NodeSensormap中的LastEventData失败：")+
                             tempQuery.lastError().text());
        else
            emit sigInfo("INFO:成功更新NodeSensormap中的LastEventData");
    }
    else
        emit sigInfo("INFO:传感器数据未发生变化，不对NodeSensormap中的LastEventData进行更新");
}

SensorDataProcess::~SensorDataProcess()
{
    delete mapRefSensorIDVirtualSensorName;
    delete mapIDInNodeSensorMap_Event;
}
